﻿//========================================================= 
/**@file H002PinCmdDriver.h
 * @brief H002密码键盘指令
 * 
 * @date 2016-10-03   11:42:49
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_H002PINCMDDRIVER_H_
#define _LIBZHOUYB_H002PINCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../pinpad/H002PinPadDevAdapter.h"
using zhou_yb::application::pinpad::H002PinPadDevAdapter;

#include "../../../extension/security/Key_Provider.h"
using zhou_yb::extension::security::Key_Provider;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// H002密码键盘命令
class H002PinCmdDriver : 
    public CommonCmdDriver,
    public BaseDevAdapterBehavior<IInteractiveTrans>
{
public:
    /// 默认数据
    enum DefaultDATA
    {
        /// 默认的密码长度
        PwdDefaultLength = 6
    };
    /// 将按键转换为对应的字符串描述
    static void FormatInput(byte key, ByteBuilder& input)
    {
        switch(key)
        {
        case 0x0D:
            input += "Enter";
            break;
            // 00
        case 0x4F:
            input += "00";
            break;
            // .
        case 0x2E:
            input += ".";
            break;
            // cancel
        case 0x1B:
            input += "Cancel";
            break;
            // correct
        case 0x08:
            input += "Correct";
            break;
        case 0x2A:
        case 0x4E:
            input += "*";
            break;
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '0':
            input += key;
            break;
        default:
            break;
        }
    }
protected:
    PinDevCmdAdapter _pinCmdAdapter;
    H002PinPadDevAdapter _pinAdapter;
    ByteBuilder _inputCache;
public:
    H002PinCmdDriver() : CommonCmdDriver()
    {
        _errGetter.Add(_pinAdapter).Select("PinCMD", _pinCmdAdapter);
        select_helper<LoggerSetter::SelecterType>::select(_logSetter),
            _pinCmdAdapter, _pinAdapter;
        _pinAdapter.SelectDevice(_pinCmdAdapter);

        _RegisteAdapterCMD(H002PinCmdDriver);

        Ref<Command> cacheCmd = _MakeCMD(H002PinCmdDriver, ClearInputCache);
        _RegisteCMD(H002PinCmdDriver, Beep);
        _RegisteCMD(H002PinCmdDriver, SetSerialNumber);
        _RegisteCMD(H002PinCmdDriver, GetSerialNumber);
        _RegisteCMD(H002PinCmdDriver, SetAppID);
        _RegisteCMD(H002PinCmdDriver, GetAppID);
        _RegisteCMD(H002PinCmdDriver, GetVersion);
        _RegisteCMD(H002PinCmdDriver, ResetMK);
        _RegisteCMD(H002PinCmdDriver, UpdateMainKey);
        _RegisteCMD(H002PinCmdDriver, UpdateEncryptedMainKey);
        _RegisteCMD(H002PinCmdDriver, UpdateEncryptedWorkKey);
        _RegisteCMD(H002PinCmdDriver, UpdateWorkKey);
        _RegisteCMD(H002PinCmdDriver, Crypt);
        _RegisteCMD(H002PinCmdDriver, GetMAC);
        _RegisteCMD(H002PinCmdDriver, GetKCV);
        _RegisteCMD(H002PinCmdDriver, Input);
        _RegisteCMD(H002PinCmdDriver, InputPassword);
        _RegisteCMD(H002PinCmdDriver, InputPinblock);
        _RegisteCMD(H002PinCmdDriver, WaitPassword)->PrefixBind(cacheCmd);
        _RegisteCMD(H002PinCmdDriver, WaitPinblock)->PrefixBind(cacheCmd);
        _RegisteCMD(H002PinCmdDriver, WaitInput)->PrefixBind(cacheCmd);
        _RegisteCMD(H002PinCmdDriver, GetPassword);
        _RegisteCMD(H002PinCmdDriver, GetPinblock);
        _RegisteCMD(H002PinCmdDriver, CancelInput)->Bind(cacheCmd, ComplexCommand::RunOnAlways);
        _RegisteCMD(H002PinCmdDriver, Reset);
        _RegisteCMD(H002PinCmdDriver, WaitKey);
    }
    LC_CMD_ADAPTER_INVOKE(IInteractiveTrans, _pinCmdAdapter);
    /// 蜂鸣器控制
    LC_CMD_METHOD(Beep)
    {
        return _pinAdapter.Beep();
    }
    /**
     * @brief 设置序列号
     * @date 2016-11-18 13:45
     * 
     * @param [in] IsHex : bool [default:false] 序列号是否以16进制格式直接写入
     * @param [in] SerialNumber : hex 需要设置的新序列号
     */
    LC_CMD_METHOD(SetSerialNumber)
    {
        string sNumber;
        ASSERT_FuncErrInfo(arg.Get("SerialNumber", sNumber),
            DeviceError::ArgIsNullErr, "SerialNumber字段为空");
        
        ByteBuilder serialNumber(8);
        bool isHex = arg["IsHex"].To<bool>(false);
        if(isHex)
        {
            ByteConvert::FromAscii(sNumber.c_str(), serialNumber);
        }
        else
        {
            serialNumber = sNumber.c_str();
        }
        return _pinAdapter.SetSerialNumber(serialNumber);
    }
    /**
     * @brief 获取序列号
     * @date 2016-11-18 13:47
     * 
     * @param [in] IsHex : bool [default:false] 序列号是否直接以16进制格式的字符串导出
     *
     * @retval SerialNumber : hex 获取到的序列号
     */
    LC_CMD_METHOD(GetSerialNumber)
    {
        ByteBuilder serialNumber(8);
        bool lastVal = _pinCmdAdapter.IsAllowFold;
        _pinCmdAdapter.IsAllowFold = false;
        bool bOK = _pinAdapter.GetSerialNumber(serialNumber);
        _pinCmdAdapter.IsAllowFold = lastVal;
        ASSERT_Func(bOK);
        bool isHex = arg["IsHex"].To<bool>(false);
        ByteConvert::ToString(isHex, serialNumber);
        rlt.Put("SerialNumber", serialNumber.GetString());
        return true;
    }
    /**
     * @brief 设置应用ID
     * @date 2016-11-18 14:10
     * 
     * @param [in] AppID : hex 需要设置的应用ID
     */
    LC_CMD_METHOD(SetAppID)
    {
        return true;
    }
    /**
     * @brief 获取应用ID
     * @date 2016-11-18 14:11
     * 
     * @retval AppID : hex 获取到的应用ID
     */
    LC_CMD_METHOD(GetAppID)
    {
        return true;
    }
    /**
     * @brief 获取设备版本
     * @date 2016-11-28 23:35
     *
     * @param [in] IsHex : bool [default:false] 是否直接以16进制格式的字符串导出
     * 
     * @retval Version : hex 获取到的版本信息
     */
    LC_CMD_METHOD(GetVersion)
    {
        ByteBuilder version(8);
        if(!_pinAdapter.GetVersion(version))
            return false;
        bool isHex = arg["IsHex"].To<bool>(false);
        ByteConvert::ToString(isHex, version);
        rlt.Put("Version", version.GetString());
        return true;
    }
    /**
     * @brief 重置主密钥
     * @date 2016-11-18 10:47
     * 
     * @param [in] MkIndex : byte [default:ALL] 需要重置的主密钥索引
     * @warning 没有该键值则重置所有密钥为初始值 0x40 + mkIndex
     * 
     * @param [in] MKey : hex 需要重置的主密钥新值
     * @param [in] Algorithm : string 密钥算法标识
     * - Algorithm算法:
     *  - DES
     *  - SM4
     * .
     */
    LC_CMD_METHOD(ResetMK)
    {
        const byte MK_ALL = 'A';
        byte mkIndex = arg["MkIndex"].To<byte>(MK_ALL);
        string sKey;
        if(!arg.Get("MKey", sKey) || mkIndex == MK_ALL)
        {
            return _pinAdapter.ResetMK(mkIndex);
        }
        string sMode;
        ASSERT_FuncErrInfo(arg.Get("Algorithm", sMode),
            DeviceError::ArgErr, "缺少参数:Algorithm");
        
        H002PinPadDevAdapter::AlgorithmMode mode = H002PinPadDevAdapter::StringToAlgorithmMode(sMode.c_str());

        ASSERT_FuncErrInfo(mode != H002PinPadDevAdapter::UnknownMode,
            DeviceError::ArgFormatErr, "Algorithm 错误");
        
        ByteBuilder mkVal(16);
        DevCommand::FromAscii(sKey.c_str(), mkVal);
        return _pinAdapter.ResetMK(mkIndex, mkVal, mode);
    }
    /**
     * @brief 明文更新主密钥
     * @date 2016-11-28 22:50
     * 
     * @param [in] MkIndex : byte 需要更新的主密钥值
     * @param [in] OldMKey : hex 更新的主密钥原始值
     * @warning 没有该键值则默认为密钥重置后的初始值
     * 
     * @param [in] MKey : hex 更新的主密钥值
     * @param [in] Algorithm : string 密钥算法标识
     * - Algorithm算法:
     *  - DES
     *  - SM4
     * .
     * @param [in] IsKCV : bool [default:false] 是否需要主密钥的KCV
     * 
     * @retval KCV : hex 设备返回的主密钥的KCV  
     */
    LC_CMD_METHOD(UpdateMainKey)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        string sOldKey;
        ByteBuilder oldKey(16);
        if(arg.Get("OldMKey", sOldKey))
        {
            DevCommand::FromAscii(sOldKey.c_str(), oldKey);
            ASSERT_FuncErrInfo(!oldKey.IsEmpty(), DeviceError::ArgIsNullErr, "OldMKey字段为空");
        }
        else
        {
            oldKey.Append(_itobyte(0x40 + mkIndex), 16);
        }
        string sNewKey = arg["MKey"].To<string>();
        ByteBuilder newKey(16);
        DevCommand::FromAscii(sNewKey.c_str(), newKey);
        ASSERT_FuncErrInfo(!newKey.IsEmpty(), DeviceError::ArgIsNullErr, "MKey字段为空");

        string sMode = arg["Algorithm"].To<string>();
        H002PinPadDevAdapter::AlgorithmMode mode = H002PinPadDevAdapter::StringToAlgorithmMode(sMode.c_str());
        ASSERT_FuncErrInfo(mode != H002PinPadDevAdapter::UnknownMode,
            DeviceError::ArgFormatErr, "Algorithm 错误");

        bool isKcv = arg["IsKCV"].To<bool>();
        bool bMK = false;
        if(isKcv)
        {
            bMK = _pinAdapter.UpdateMainKey(mkIndex, oldKey, newKey, mode);
        }
        else
        {
            ByteBuilder kcv(8);
            bMK = _pinAdapter.UpdateMainKey_KCV(mkIndex, oldKey, newKey, mode, &kcv);
            if(bMK)
            {
                rlt.Put("KCV", ArgConvert::ToString(kcv));
            }
        }
        return bMK;
    }
    /**
     * @brief 密文更新主密钥
     * @date 2016-11-28 23:00
     * 
     * @param [in] MkIndex : byte 需要更新的主密钥ID
     * @param [in] MKey : hex 需要更新的工作密钥密文
     * @param [in] Algorithm : string 密钥算法标识
     * - Algorithm算法:
     *  - DES
     *  - SM4
     * .
     * @param [in] KCV : hex [default:""] 工作密钥KCV(可选)
     * 
     * @retval KCV : hex 设备返回的KCV
     */
    LC_CMD_METHOD(UpdateEncryptedMainKey)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        string sMK = arg["MKey"].To<string>();
        string sMode = arg["Algorithm"].To<string>();

        ByteBuilder mk(16);
        DevCommand::FromAscii(sMK.c_str(), mk);
        ASSERT_FuncErrInfo(!mk.IsEmpty(), DeviceError::ArgIsNullErr, "MKey字段为空");
        
        H002PinPadDevAdapter::AlgorithmMode mode = H002PinPadDevAdapter::StringToAlgorithmMode(sMode.c_str());
        ASSERT_FuncErrInfo(mode != H002PinPadDevAdapter::UnknownMode,
            DeviceError::ArgFormatErr, "Algorithm 错误");

        string sKCV;
        ByteBuilder kcv(8);
        bool bRet = false;
        bool hasKCV = false;
        ByteBuilder mkKcv(8);
        if(arg.Get("KCV", sKCV))
        {
            DevCommand::FromAscii(sKCV.c_str(), mkKcv);
            hasKCV = !mkKcv.IsEmpty();
        }
        if(hasKCV)
        {
            bRet = _pinAdapter.UpdateEncryptedMainKey(mkIndex, mk, mkKcv, mode, &kcv);
        }
        else
        {
            bRet = _pinAdapter.UpdateEncryptedMainKey(mkIndex, mk, mode, &kcv);
        }
        if(!bRet)
            return false;
        rlt.Put("KCV", ArgConvert::ToString(kcv));
        return true;
    }
    /**
     * @brief 密文更新工作密钥
     * @date 2016-11-18 14:21
     * 
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte 工作密钥索引
     * @param [in] WKey : hex 需要更新的工作密钥密文
     * @param [in] Algorithm : string 密钥算法标识
     * - Algorithm算法:
     *  - DES
     *  - SM4
     * .
     * @param [in] KCV : hex [default:""] 工作密钥KCV(可选)
     * 
     * @retval KCV : hex 设备返回的KCV  
     */
    LC_CMD_METHOD(UpdateEncryptedWorkKey)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        string sWK = arg["WKey"].To<string>();
        string sMode = arg["Algorithm"].To<string>();

        ByteBuilder wk(16);
        DevCommand::FromAscii(sWK.c_str(), wk);
        ASSERT_FuncErrInfo(!wk.IsEmpty(), DeviceError::ArgIsNullErr, "WKey字段为空");
        
        H002PinPadDevAdapter::AlgorithmMode mode = H002PinPadDevAdapter::StringToAlgorithmMode(sMode.c_str());
        ASSERT_FuncErrInfo(mode != H002PinPadDevAdapter::UnknownMode,
            DeviceError::ArgFormatErr, "Algorithm 错误");

        string sKCV;
        ByteBuilder kcv(8);
        ByteBuilder wkKcv(8);
        bool bRet = false;
        bool hasKCV = false;
        if(arg.Get("KCV", sKCV))
        {
            DevCommand::FromAscii(sKCV.c_str(), wkKcv);
            hasKCV = !wkKcv.IsEmpty();
        }
        if(hasKCV)
        {
            bRet = _pinAdapter.UpdateEncryptedWorkKey(mkIndex, wkIndex, wk, wkKcv, mode, &kcv);
        }
        else
        {
            bRet = _pinAdapter.UpdateEncryptedWorkKey(mkIndex, wkIndex, wk, mode, &kcv);
        }
        if(!bRet)
            return false;
        rlt.Put("KCV", ArgConvert::ToString(kcv));
        return true;
    }
    /**
     * @brief 明文下载工作密钥
     * @date 2016-11-22 22:01
     * 
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte 工作密钥索引
     * @param [in] WKey : hex 工作密钥明文
     * @param [in] Algorithm : string 密钥算法标识
     * - Algorithm算法:
     *  - DES
     *  - SM4
     * .
     * 
     * @retval KCV : hex 工作密钥KCV
     */
    LC_CMD_METHOD(UpdateWorkKey)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        string sWK = arg["WKey"].To<string>();
        string sMode = arg["Algorithm"].To<string>();

        ByteBuilder wk(16);
        DevCommand::FromAscii(sWK.c_str(), wk);
        ASSERT_FuncErrInfo(!wk.IsEmpty(), DeviceError::ArgIsNullErr, "WKey字段为空");
        
        H002PinPadDevAdapter::AlgorithmMode mode = H002PinPadDevAdapter::StringToAlgorithmMode(sMode.c_str());
        ASSERT_FuncErrInfo(mode != H002PinPadDevAdapter::UnknownMode,
            DeviceError::ArgFormatErr, "Algorithm 错误");

        ByteBuilder kcv(8);
        if(!_pinAdapter.UpdateWorkKey(mkIndex, wkIndex, wk, mode, &kcv))
            return false;
        rlt.Put("KCV", ArgConvert::ToString(kcv));
        return true;
    }
    /**
     * @brief 加解密数据
     * @date 2016-11-18 14:39
     * 
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte 工作密钥索引
     * @warning 没有该字段或者值为FF时则认为是使用主密钥加密数据
     *
     * @param [in] Algorithm : string 算法
     * - 算法:
     *  - DES
     *  - SM4
     * .
     * @param [in] Mode : string 加解密方式
     * - 方式:
     *  - E,Enc,Encrypt 加密
     *  - D,Dec,Decrypt 解密
     * .
     * @param [in] IV : hex 使用CBC模式时的向量
     * @warning 有该值时表示使用CBC方式 
     *
     * @param [in] DATA : hex 需要加密的数据 
     *
     * @retval DATA : hex 处理后的数据
     */
    LC_CMD_METHOD(Crypt)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>(0xFF);
        string sAlgorithm = arg["Algorithm"].To<string>();
        ASSERT_FuncErrInfo(sAlgorithm.length() > 0,
            DeviceError::ArgIsNullErr, "缺少参数:Algorithm");
        int indexDES = 0;
        if(StringConvert::Compare(sAlgorithm.c_str(), "DES", true))
        {
            indexDES = 0;
        }
        else if(StringConvert::Compare(sAlgorithm.c_str(), "SM4", true))
        {
            indexDES = 1;
        }
        else
        {
            _logErr(DeviceError::ArgFormatErr, "Algorithm 错误");
            return false;
        }

        string sIV = "";
        int indexECB = 0;
        if(arg.Get("IV", sIV))
        {
            indexECB = 1;
        }

        string sMode = arg["Mode"].To<string>();
        ASSERT_FuncErrInfo(sMode.length() > 0,
            DeviceError::ArgIsNullErr, "缺少参数:Mode");
        int indexENC = 0;
        if(StringConvert::StartWith(sMode.c_str(), "E", true))
        {
            indexENC = 0;
        }
        else if(StringConvert::StartWith(sMode.c_str(), "D", true))
        {
            indexENC = 1;
        }
        else
        {
            _logErr(DeviceError::ArgFormatErr, "Mode 错误");
            return false;
        }
        const byte CRYPT_MODE[2][2][2] = {
            {
                {
                    H002PinPadDevAdapter::DES_ECB_EncMode,
                    H002PinPadDevAdapter::DES_ECB_DecMode
                },
                {
                    H002PinPadDevAdapter::DES_CBC_EncMode,
                    H002PinPadDevAdapter::DES_CBC_DecMode
                },
            },
            {
                {
                    H002PinPadDevAdapter::SM4_ECB_EncMode,
                    H002PinPadDevAdapter::SM4_ECB_DecMode
                },
                {
                    H002PinPadDevAdapter::SM4_CBC_EncMode,
                    H002PinPadDevAdapter::SM4_CBC_DecMode
                },
            }
        };
        H002PinPadDevAdapter::CryptMode mode = static_cast<H002PinPadDevAdapter::CryptMode>(CRYPT_MODE[indexDES][indexECB][indexENC]);

        size_t ivlen = (indexDES == 0 ? 8 : 16);
        ByteBuilder iv(16);
        if(indexECB != 0)
        {
            DevCommand::FromAscii(sIV.c_str(), iv);
            ASSERT_FuncErrInfo(iv.GetLength() >= ivlen,
                DeviceError::ArgLengthErr, "IV长度错误");
        }
        else
        {
            iv.Append(0x00, ivlen);
        }
        string sData = arg["DATA"].To<string>();
        ASSERT_FuncErrInfo(sData.length() > 0,
            DeviceError::ArgIsNullErr, "缺少字段:DATA");

        ByteBuilder data(32);
        DevCommand::FromAscii(sData.c_str(), data);

        ByteBuilder buff(16);
        bool bCrypt = false;
        if(wkIndex == 0xFF)
        {
            for(size_t i = 0;i < data.GetLength(); i += ivlen)
            {
                bCrypt = _pinAdapter.MKeyCrypt(mkIndex, mode, iv, data, buff);
                if(!bCrypt)
                    return false;
            }
        }
        else
        {
            for(size_t i = 0;i < data.GetLength(); i += ivlen)
            {
                bCrypt = _pinAdapter.WKeyCrypt(mkIndex, wkIndex, mode, iv, data, buff);
                if(!bCrypt)
                    return false;
            }
        }
        rlt.Put("DATA", ArgConvert::ToString(buff));
        return true;
    }
    /**
     * @brief 计算MAC值
     * @date 2016-11-18 15:51
     * 
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte [default:0xFF] 工作密钥索引
     * @warning 没有该字段或者值为FF时表示使用主密钥计算
     * 
     * @param [in] Algorithm : string 算法
     * - 算法:
     *  - DES
     *  - SM4
     * .
     * @param [in] Pad : byte [default:0x00] 后补字节
     * @param [in] IV : hex 向量
     * @param [in] DATA : hex 计算MAC的数据源
     * 
     * @retval MAC : hex 计算后的MAC值
     * @retval KeyLength : size_t 计算MAC的长度
     */
    LC_CMD_METHOD(GetMAC)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>(0xFF);
        string sAlgorithm = arg["Algorithm"].To<string>();
        H002PinPadDevAdapter::AlgorithmMode mode = H002PinPadDevAdapter::StringToAlgorithmMode(sAlgorithm.c_str());
        ASSERT_FuncErrInfo(mode != H002PinPadDevAdapter::UnknownMode,
            DeviceError::ArgFormatErr, "Algorithm 错误");
        byte pad = arg["Pad"].To<byte>(0x00);
        string sIV = arg["IV"].To<string>();
        size_t ivlen = 16;
        ByteBuilder iv(8);
        DevCommand::FromAscii(sIV.c_str(), iv);
        if(iv.IsEmpty())
            iv.Append(0x00, ivlen);
        ASSERT_FuncErrInfo(iv.GetLength() >= ivlen, DeviceError::ArgLengthErr, "IV长度错误");
        ByteConvert::Fill(iv, ivlen, true);

        string sData = arg["DATA"].To<string>();
        ByteBuilder data(16);
        DevCommand::FromAscii(sData.c_str(), data);
        ByteConvert::FillN(data, 0, ivlen, pad);

        ByteBuilder mac(8);
        size_t len = 0;
        if(!_pinAdapter.GetMAC(mkIndex, wkIndex, iv, data, mac, &len))
        {
            return false;
        }
        rlt.Put("MAC", ArgConvert::ToString(mac));
        rlt.Put("KeyLength", ArgConvert::ToString(len));
        return true;
    }
    /**
     * @brief 获取密钥的KCV值
     * @date 2016-11-28 23:47
     * 
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte [default:0xFF] 工作密钥索引
     * @warning 没有该字段或者值为FF时表示使用主密钥计算
     * 
     * @retval KCV : hex 设备计算出来的KCV
     */
    LC_CMD_METHOD(GetKCV)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>(0xFF);
        ByteBuilder kcv(8);
        if(!_pinAdapter.GetKCV(mkIndex, wkIndex, kcv))
            return false;
        rlt.Put("KCV", ArgConvert::ToString(kcv));
        return true;
    }
    /**
     * @brief 明文输入数据
     * @date 2016-11-28 23:44
     * 
     * @param [in] IsEnter : bool [default:true] 是否需要按确认键返回
     * @param [in] IsClearAll : bool [default:true] 是否退格时清除所有数据
     * @param [in] IsEnableEnter : bool [default:true] 是否允许未到最大长度时按确认键
     * @param [in] PwdLength : size_t [default:6] 期望输入的密码长度
     * 
     * @retval Input : string 输入的明文数据
     */
    LC_CMD_METHOD(Input)
    {
        bool isEnter = arg["IsEnter"].To<bool>(true);
        bool isClearAll = arg["IsClearAll"].To<bool>(true);
        bool isEnableEnter = arg["IsEnableEnter"].To<bool>(true);
        size_t pinlen = arg["PwdLength"].To<size_t>(PwdDefaultLength);

        ByteBuilder input(8);
        if(!_pinAdapter.Input(isEnter, pinlen, isClearAll, !isEnableEnter, input))
            return false;
        rlt.Put("Input", ArgConvert::ToString(input));
        return true;
    }
    /**
     * @brief 密文输入密码(不带*号返回)
     * @date 2016-11-28 23:07
     * 
     * @param [in] MkIndex : byte 主密钥号
     * @param [in] WkIndex : byte 工作密钥号
     * @param [in] PwdLength : size_t [default:6] 期望输入的密码长度
     * @param [in] IsReVoice : bool [default:false] 是否语音提示再次输入密码
     * @param [in] IsEnter : bool [default:true] 是否需要按确认键后返回
     * @param [in] IsClearAll : bool [default:true] 是否退格时清除所有数据
     * @param [in] IsEnableEnter : bool [default:true] 是否允许未到最大长度时按确认键
     * 
     * @retval Pwd : hex 输入的密文密码
     * @retval PwdLength : size_t 实际输入的密码长度
     */
    LC_CMD_METHOD(InputPassword)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        size_t pwdlen = arg["PwdLength"].To<size_t>(PwdDefaultLength);
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        bool isEnter = arg["IsEnter"].To<bool>(true);
        bool isClearAll = arg["IsClearAll"].To<bool>(true);
        bool isEnableEnter = arg["IsEnableEnter"].To<bool>(true);

        ByteBuilder pin(8);
        size_t pinlen = 0;
        if(!_pinAdapter.InputPassword(mkIndex, wkIndex, pwdlen, isReVoice, isEnter, isClearAll, !isEnableEnter, pin, pinlen))
            return false;

        rlt.Put("Pwd", ArgConvert::ToString(pin));
        rlt.Put("PwdLength", ArgConvert::ToString(pinlen));
        return true;
    }
    /**
     * @brief 输入密码获取PINBLOCK
     * @date 2016-11-28 23:16
     * 
     * @param [in] Accno : string 客户帐号
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte 工作密钥索引
     * @param [in] PwdLength : size_t [default:6] 期望输入的密码长度
     * @param [in] IsReVoice : bool [default:false] 是否语音提示再次输入密码
     * @param [in] IsEnter : bool [default:true] 是否需要按确认键后返回
     * @param [in] IsClearAll : bool [default:true] 是否退格时清除所有数据
     * @param [in] IsEnableEnter : bool [default:true] 是否允许未到最大长度时按确认键
     * 
     * @retval PinBlock : hex 获取到的PINBLOCK
     */
    LC_CMD_METHOD(InputPinblock)
    {
        string sAccno = arg["Accno"].To<string>();
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        size_t pwdlen = arg["PwdLength"].To<size_t>(PwdDefaultLength);
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        bool isEnter = arg["IsEnter"].To<bool>(true);
        bool isClearAll = arg["IsClearAll"].To<bool>(true);
        bool isEnableEnter = arg["IsEnableEnter"].To<bool>(true);

        ByteBuilder accno(8);
        Key_Provider::FormatAnsiAccno(sAccno.c_str(), accno);

        ByteBuilder pinblock(8);
        if(!_pinAdapter.InputPinblock(accno, mkIndex, wkIndex, pwdlen, isReVoice, isEnter, isClearAll, !isEnableEnter, pinblock))
            return false;
        rlt.Put("PinBlock", ArgConvert::ToString(pinblock));
        return true;
    }
    /**
     * @brief 开始输入密文密码(数据通过GetPassword获取)
     * @date 2016-11-22 18:07
     * 
     * @param [in] PwdLength : size_t [default:6] 期望输入的密码长度
     * @param [in] IsReVoice : bool [default:false] 是否语音提示再次输入密码
     * @param [in] IsEnter : bool [default:true] 是否需要按确认键后返回
     * @param [in] IsClearAll : bool [default:true] 是否退格时清除所有数据
     * @param [in] IsEnableEnter : bool [default:true] 是否允许未到最大长度时按确认键
     */
    LC_CMD_METHOD(WaitPassword)
    {
        size_t pwdlen = arg["PwdLength"].To<size_t>(PwdDefaultLength);
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        bool isEnter = arg["IsEnter"].To<bool>(true);
        bool isClearAll = arg["IsClearAll"].To<bool>(true);
        bool isEnableEnter = arg["IsEnableEnter"].To<bool>(true);

        return _pinAdapter.WaitPassword(pwdlen, isReVoice, isEnter, isClearAll, !isEnableEnter);
    }
    /**
     * @brief 开始输入密码获取PINBLOCK(数据通过GetPinblock获取)
     * @date 2016-11-20 10:57
     * 
     * @param [in] PwdLength : size_t [default:6] 期望输入的密码长度
     * @param [in] IsReVoice : bool [default:false] 是否语音提示再次输入
     * @param [in] IsEnter : bool [default:true] 是否需要按确认键才返回
     * @param [in] IsClearAll : bool [default:true] 是否退格时清除所有数据
     * @param [in] IsEnableEnter : bool [default:true] 是否允许未到最大长度时按确认键
     */
    LC_CMD_METHOD(WaitPinblock)
    {
        size_t pwdlen = arg["PwdLength"].To<size_t>(PwdDefaultLength);
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        bool isEnter = arg["IsEnter"].To<bool>(true);
        bool isClearAll = arg["IsClearAll"].To<bool>(true);
        bool isEnableEnter = arg["IsEnableEnter"].To<bool>(true);

        bool bOK = _pinAdapter.WaitPinblock(pwdlen, isReVoice, isEnter, isClearAll, !isEnableEnter);
        return bOK;
    }
    /**
     * @brief 开始输入明文密码(数据通过GetInput获取)
     * @date 2016-11-22 16:02
     *
     * @param [in] IsReVoice [default:false] 是否需要提示再次输入密码
     */
    LC_CMD_METHOD(WaitInput)
    {
        bool isReVoice = arg["IsReVoice"].To<bool>(false);
        return _pinAdapter.WaitInput(isReVoice);
    }
    /**
     * @brief 获取按键后的密文密码(前置接口为WaitPassword)
     * @date 2016-11-28 23:13
     * 
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte 工作密钥索引
     * 
     * @retval Pwd : hex 输入的密文密码
     * @retval PwdLength : size_t 输入的密码长度
     */
    LC_CMD_METHOD(GetPassword)
    {
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        ByteBuilder pin(8);
        size_t pinlen = 0;
        if(!_pinAdapter.GetPassword(mkIndex, wkIndex, pin, pinlen))
            return false;
        rlt.Put("Pwd", ArgConvert::ToString(pin));
        rlt.Put("PwdLength", ArgConvert::ToString(pinlen));
        return true;
    }
    /**
     * @brief 获取客户输入的PINBLOCK信息(前置接口为WaitPinblock)
     * @date 2016-11-28 23:37
     * 
     * @param [in] Accno : string 主帐号信息
     * @param [in] MkIndex : byte 主密钥索引
     * @param [in] WkIndex : byte 工作密钥索引
     * 
     * @retval PinBlock : hex 获取到的PINBLOCK数据
     * @retval KeyLength : size_t 加密密码的密钥长度
     */
    LC_CMD_METHOD(GetPinblock)
    {
        string sAccno = arg["Accno"].To<string>();
        byte mkIndex = arg["MkIndex"].To<byte>();
        byte wkIndex = arg["WkIndex"].To<byte>();
        ByteBuilder pin(8);
        size_t keylen = 0;

        ByteBuilder accno(8);
        Key_Provider::FormatAnsiAccno(sAccno.c_str(), accno);
        if(!_pinAdapter.GetPinblock(mkIndex, wkIndex, accno, pin, &keylen))
            return false;
        rlt.Put("PinBlock", ArgConvert::ToString(pin));
        rlt.Put("KeyLength", ArgConvert::ToString(keylen));
        return true;
    }
    /**
     * @brief 取消输入
     * @date 2016-11-28 23:42
     */
    LC_CMD_METHOD(CancelInput)
    {
        return _pinAdapter.CancelInput();
    }
    /**
     * @brief 关闭密码键盘
     * @date 2016-11-28 23:42
     */
    LC_CMD_METHOD(Reset)
    {
        return _pinAdapter.Reset();
    }
    /// 清空当前已输入的按键
    LC_CMD_METHOD(ClearInputCache)
    {
        _inputCache.Clear();
        return true;
    }
    /**
     * @brief 等待获取按键输入
     * @date 2016-11-20 11:11
     * 
     * @retval Key : string 当前输入的按键描述
     * @retval KeyCode : byte 输入的按键
     */
    LC_CMD_METHOD(WaitKey)
    {
        if(_inputCache.GetLength() < 1)
        {
            if(!_pDev->Read(_inputCache))
                return false;
        }
        byte key = _inputCache[0];
        _inputCache.RemoveFront(1);

        ByteBuilder sInput(8);
        H002PinCmdDriver::FormatInput(key, sInput);
        rlt.Put("Key", sInput.GetString());
        rlt.Put("KeyCode", ArgConvert::ToString(key));
        return true;
    }
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_H002PINCMDDRIVER_H_
//========================================================= 